package com.gitee.wsl.net.ssdp.description.model.xml

import com.gitee.wsl.net.ssdp.description.xml.XmlElement
import kotlin.properties.Delegates

/**
 * Device metadata
 * @param deviceType    -  UPnP device type. Single URI.
 *                          For standard devices defined by a UPnP Forum working committee, shall begin with
 *                          “urn:schemas-upnp-org:device:” followed by the standardized device type suffix, a colon,
 *                          and an integer device version i.e. urn:schemas-upnp-org:device:deviceType:ver. The
 *                          highest supported version of the device type shall be specified.
 *                          For non-standard devices specified by UPnP vendors, shall begin with “urn:”, followed by
 *                          a Vendor Domain Name, followed by “:device:”, followed by a device type suffix, colon,
 *                          and an integer version, i.e., “urn:domain-name:device:deviceType:ver”. Period
 *                          characters in the Vendor Domain Name shall be replaced with hyphens in accordance
 *                          with RFC 2141. The highest supported version of the device type shall be specified.
 *                          The device type suffix defined by a UPnP Forum working committee or specified by a UPnP
 *                          vendor shall be <= 64 chars, not counting the version suffix and separating colon.
 * @param friendlyName  - Short description for end user. Is allowed to be localized (see ACCEPTLANGUAGE and
 *                          CONTENT-LANGUAGE header fields). Specified by UPnP vendor. String. Should be < 64 characters.
 * @param manufacturer  - Manufacturer's name. Is allowed to be localized (see ACCEPT-LANGUAGE and CONTENT-LANGUAGE
 *                          header fields). Specified by UPnP vendor. String. Should be < 64 characters.
 * @param manufacturerUrl   - Website for Manufacturer. Is allowed to have a different value depending on
 *                          language requested (see ACCEPT-LANGUAGE and CONTENT-LANGUAGE header fields).
 *                          Specified by UPnP vendor. Single URL.
 * @param modelDescription  - Long description for end user. Is allowed to be localized (see ACCEPTLANGUAGE and
 *                          CONTENT-LANGUAGE header fields). Specified by UPnP vendor. String. Should be < 128 characters.
 * @param modelName     - Model name. Is allowed to be localized (see ACCEPT-LANGUAGE and CONTENTLANGUAGE header fields).
 *                          Specified by UPnP vendor. String. Should be < 32 characters.
 * @param modelNumber   - Model number. Is allowed to be localized (see ACCEPT-LANGUAGE and CONTENT-LANGUAGE
 *                          header fields). Specified by UPnP vendor. String. Should be < 32 characters.
 * @param modelUrl      - Website for model. Is allowed to have a different value depending on language
 *                          requested (see ACCEPT-LANGUAGE and CONTENT-LANGUAGE header fields). Specified
 *                          by UPnP vendor. Single URL.
 * @param serialNumber  - Serial number. Is allowed to be localized (see ACCEPT-LANGUAGE and CONTENT-LANGUAGE header
 *                          fields). Specified by UPnP vendor. String. Should be < 64 characters.
 * @param udn           - Unique Device Name. Universally-unique identifier for the device, whether root or
 *                          embedded. shall be the same over time for a specific device instance (i.e., shall survive
 *                          reboots). shall match the field value of the NT header field in device discovery messages.
 *                          shall match the prefix of the USN header field in all discovery messages. (Clause 1,
 *                          “Discovery” explains the NT and USN header fields.) shall begin with “uuid:” followed by a
 *                          UUID suffix specified by a UPnP vendor.
 * @param upc           - Universal Product Code. 12-digit, all-numeric code that identifies the consumer
 *                          package. Managed by the Uniform Code Council. Specified by UPnP vendor. Single UPC.
 * @param iconList      - @see Icon
 */
data class DeviceDescription(
    val deviceType: String,
    val friendlyName: String,
    val manufacturer: String,
    val manufacturerUrl: String? = null,
    val modelDescription: String? = null,
    val modelName: String,
    val modelNumber: String? = null,
    val modelUrl: String? = null,
    val serialNumber: String? = null,
    val udn: String,
    val originUdn: String? = null,
    val upc: String? = null,
    val iconList: List<IconList.Icon>? = null,
    val serviceList: List<ServiceList.Service>? = null,
    val deviceList: List<DeviceDescription>? = null,
    val presentationUrl: String? = null,
    val manufacturerSpecific: MutableMap<String, String> = mutableMapOf<String, String>()
) {
    companion object {
        /**
         * Facilitates fast and flexible deserialization and conditional validation.
         */
        fun fromXml(xml: XmlElement): DeviceDescription {
            var deviceTypeS by Delegates.notNull<String>()
            var friendlyNameS by Delegates.notNull<String>()
            var manufacturerS by Delegates.notNull<String>()
            var manufacturerUrlS: String? = null
            var modelDescriptionS: String? = null
            var modelNameS by Delegates.notNull<String>()
            var modelNumberS: String? = null
            var modelUrlS: String? = null
            var serialNumberS: String? = null
            var udnS by Delegates.notNull<String>()
            var originUdnS: String? = null
            var upcS: String? = null
            var iconListO: List<IconList.Icon>? = null
            var serviceListO: List<ServiceList.Service>? = null
            var deviceListO: List<DeviceDescription>? = null
            var presentationUrlS: String? = null
            var manSpecificO = mutableMapOf<String, String>()

            xml.children?.forEach {
                when (it.tag) {
                    "deviceType" -> deviceTypeS = it.get()
                    "friendlyName" -> friendlyNameS = it.get()
                    "manufacturer" -> manufacturerS = it.get()
                    "manufacturerURL" -> manufacturerUrlS = it.getOrNull<String>()
                    "modelDescription" -> modelDescriptionS = it.getOrNull<String>()
                    "modelName" -> modelNameS = it.get()
                    "modelNumber" -> modelNumberS = it.getOrNull<String>()
                    "modelURL" -> modelUrlS = it.getOrNull<String>()
                    "serialNumber" -> serialNumberS = it.getOrNull<String>()
                    "UDN" -> udnS = it.get()
                    "originUDN" -> originUdnS = it.getOrNull<String>()
                    "UPC" -> upcS = it.getOrNull<String>()
                    "iconList" -> iconListO = IconList.fromXml(it)
                    "serviceList" -> serviceListO = ServiceList.fromXml(it)
                    "deviceList" -> deviceListO = DeviceList.fromXml(it)
                    "presentationURL" -> presentationUrlS = it.getOrNull<String>()
                    else ->  manSpecificO[it.tag] = it.get()
                }
            }
            return DeviceDescription(
                deviceType = deviceTypeS,
                friendlyName = friendlyNameS,
                manufacturer = manufacturerS,
                manufacturerUrl = manufacturerUrlS,
                modelDescription = modelDescriptionS,
                modelName = modelNameS,
                modelNumber = modelNumberS,
                modelUrl = modelUrlS,
                serialNumber = serialNumberS,
                udn = udnS,
                originUdn = originUdnS,
                upc = upcS,
                iconList = iconListO,
                serviceList = serviceListO,
                deviceList = deviceListO,
                presentationUrl = presentationUrlS,
                manufacturerSpecific = manSpecificO
            )
        }
    }
}